/**
  ******************************************************************************
  * File Name          : ethernetif.c
  * Description        : This file provides code for the configuration
  *                      of the ethernetif.c MiddleWare.
  ******************************************************************************
  * This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * Copyright (c) 2018 STMicroelectronics International N.V. 
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without 
  * modification, are permitted, provided that the following conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice, 
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of STMicroelectronics nor the names of other 
  *    contributors to this software may be used to endorse or promote products 
  *    derived from this software without specific written permission.
  * 4. This software, including modifications and/or derivative works of this 
  *    software, must execute solely and exclusively on microcontroller or
  *    microprocessor devices manufactured by or for STMicroelectronics.
  * 5. Redistribution and use of this software other than as permitted under 
  *    this license is void and will automatically terminate your rights under 
  *    this license. 
  *
  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 
  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 
  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "../arch/sys_arch.h"
#include "lwip/opt.h"         // lwIP 配置选项头文件（编译开关、参数配置）
#include "lwip/mem.h"         // lwIP 内存管理模块（内存分配/释放）
#include "lwip/pbuf.h"        // lwIP 数据包缓冲区管理（pbuf 结构体操作）
#include "lwip/memp.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "netif/etharp.h"     // lwIP ARP 协议模块（地址解析协议）
#include "lwip/ethip6.h"
#include "ethernetif.h"
#include <string.h>
#include "../../../../User/BSP/ETH_BSP/lan8720a_bsp.h"
#include "../../../../User/Driver/Debug/debug_driver.h"


// -------------------------- 外部引用变量 --------------------------
extern ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB]; // 以太网 RX/TX DMA 描述符表（外部定义，存缓冲区地址、状态等）
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];      // 以太网接收缓冲区数组（ETH_RXBUFNB 个缓冲区，每个大小 ETH_RX_BUF_SIZE）
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];      // 以太网发送缓冲区数组（同上，用于发送数据）
extern volatile ETH_DMADESCTypeDef  *DMATxDescToSet;       // 指向当前待配置的 TX DMA 描述符（外部维护发送进度）
extern volatile ETH_DMADESCTypeDef  *DMARxDescToGet;       // 指向当前待读取的 RX DMA 描述符（外部维护接收进度）
extern volatile ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;// 接收帧信息结构体（保存帧长度、段数等）


/* 网络接口名称 */
#define IFNAME0 's'
#define IFNAME1 't'


// 以太网接收信号量（中断与任务同步）
SemaphoreHandle_t ETH_Rx_xSemaphore = NULL;
// 以太网链路信号量
SemaphoreHandle_t ETH_Link_xSemaphore = NULL;

// 以太网发送信号量（可开启底层任务式发送）
static sys_sem_t tx_sem = NULL;
static sys_mbox_t eth_tx_mb = NULL;

// 以太网输入处理任务
static void ethernetif_input(void *pParams);
// 以太网发送处理任务
static void ethernetif_output(void *pParams);
// 以太网链路处理任务
static void ETH_Link_Task(void * pParams);
// ARP 定时器回调（定期清理 ARP 缓存，lwIP 协议要求）
static void arp_timer(void *arg);



/*******************************************************************************
                       LL驱动接口（LwIP协议栈 --> 以太网）
*******************************************************************************/
/**
 * 底层硬件初始化
 * 被ethernetif_init()调用。
 *
 * @param netif lwIP 网络接口结构体（包含网口 MAC、MTU、标志等信息）
 */
static void low_level_init(struct netif *netif)
{
	/* 以太网硬件初始化 */
  	if (WHT_ETH_BSP_Init() == SUCCESS)
	{
    	/* 设置网络链接标志 */
    	netif->flags |= NETIF_FLAG_LINK_UP;
  	}

#if LWIP_ARP || LWIP_ETHERNET
    // 配置 lwIP 网口基本参数
    netif->hwaddr_len = ETH_HWADDR_LEN;  // MAC 地址长度（固定为 6 字节，以太网标准）
  	/* 设置MAC硬件地址 */
  	netif->hwaddr[0] =  MAC_ADDR0;
  	netif->hwaddr[1] =  MAC_ADDR1;
  	netif->hwaddr[2] =  MAC_ADDR2;
  	netif->hwaddr[3] =  MAC_ADDR3;
  	netif->hwaddr[4] =  MAC_ADDR4;
  	netif->hwaddr[5] =  MAC_ADDR5;

    netif->mtu = MAX_ETH_PAYLOAD;  // 配置 MTU（与宏定义一致，最大帧载荷长度）
    // 网口功能标志：支持广播、支持 ARP 协议
	#if LWIP_ARP
		netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
	#else 
		netif->flags |= NETIF_FLAG_BROADCAST;
	#endif /* LWIP_ARP */

	/* 接收帧的二值信号量 */
  	if (sys_sem_new(&ETH_Rx_xSemaphore , 0) == ERR_OK)
	{
		PRINT_DEBUG("ETH_Rx_xSemaphore ok\n");
	}

	/* 发送帧的二值信号量 */
  	if (sys_sem_new(&tx_sem , 0) == ERR_OK)
	{
		PRINT_DEBUG("tx_sem ok\n");
	}
  	if(sys_mbox_new(&eth_tx_mb , 50) == ERR_OK)
	{
		PRINT_DEBUG("eth_tx_mb ok\n");
	}

	/* 链路变化的二值信号量 */
	if (sys_sem_new(&ETH_Link_xSemaphore , 0) == ERR_OK)
	{
		PRINT_DEBUG("ETH_Link_xSemaphore ok\n");
	}
#endif /* LWIP_ARP || LWIP_ETHERNET */

    // 配置以太网 MAC 硬件地址（将 lwIP 网口的 MAC 写入 STM32 MAC 寄存器）
    ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr);

    // 初始化 DMA 描述符链（链式结构管理多个缓冲区，支持连续收发）
    ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); // 初始化 TX 描述符链
    ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); // 初始化 RX 描述符链

    // 使能所有 RX 描述符的接收中断（有数据接收时触发中断，释放信号量）
    for (int i = 0; i < ETH_RXBUFNB; i++)
    {
        ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
    }

    // （可选）使能硬件校验和计算（减少 CPU 负担，需 lwIP 配置 CHECKSUM_BY_HARDWARE 宏）
#ifdef CHECKSUM_BY_HARDWARE
    for (int i = 0; i < ETH_TXBUFNB; i++)
    {
        // 配置 TX 描述符：对 TCP/UDP/ICMP 包进行全校验和插入
        ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
    }
#endif

#if LWIP_ARP || LWIP_ETHERNET
  	// 创建以太网处理任务（负责读取接收数据并提交给 lwIP）
	/* 名字 函数  函数参数 任务栈大小 任务的优先级*/
	sys_thread_new("LWIP_Input_Task", ethernetif_input, netif, NETIF_IN_TASK_STACK_SIZE, NETIF_IN_TASK_PRIORITY);
	sys_thread_new("LWIP_Output_Task", ethernetif_output, netif, NETIF_OUT_TASK_STACK_SIZE, NETIF_OUT_TASK_PRIORITY);
	sys_thread_new("ETH_Link_Task", ETH_Link_Task, netif, configMINIMAL_STACK_SIZE, tskIDLE_PRIORITY + 1);
#endif /* LWIP_ARP || LWIP_ETHERNET */
	/* 启动以太网MAC和DMA发送/接收 */
	ETH_Start();
}

/**
 * 底层数据包发送（被 lwIP 调用，将 pbuf 中的数据通过硬件发送）
 *
 * @param netif lwIP 网络接口结构体（当前发送网口）
 * @param p 要发送的 MAC 数据包（例如包含 MAC 地址和类型的 IP 数据包）
 * @return 成功返回ERR_OK，否则err_t值
 *
 * @note 如果在介质访问控制（MAC）的直接内存访问（DMA）队列已满时在此处返回ERR_MEM，可能会导致奇怪的结果。
 * 你或许可以考虑等待DMA队列中有可用空间，因为协议栈不会重试发送因内存故障而丢弃的数据包（除了传输控制协议（TCP）计时器的情况外）。
 */
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
	static xSemaphoreHandle xTxSemaphore = NULL; // 发送同步信号量（避免多任务同时发送冲突）
  	struct pbuf *q;                         // 遍历 pbuf 链表的指针
	uint8_t *buffer;                        // 指向当前 DMA 发送缓冲区的地址
	volatile ETH_DMADESCTypeDef *DmaTxDesc; // 指向当前 TX DMA 描述符
  	uint16_t framelength = 0;               // 以太网帧总长度
  	uint32_t bufferoffset = 0;              // 当前缓冲区的偏移量（已使用字节数）
  	uint32_t byteslefttocopy = 0;           // 剩余待复制的字节数
  	uint32_t payloadoffset = 0;             // 当前 pbuf  payload 的偏移量（已复制字节数）

  	buffer =  (uint8_t*)(DMATxDescToSet->Buffer1Addr);
  	DmaTxDesc = DMATxDescToSet;

    // 初始化发送信号量（首次调用时创建，二进制信号量）
    if (xTxSemaphore == NULL)
    {
        vSemaphoreCreateBinary(xTxSemaphore);
    }

    // 获取发送信号量（保证同一时间只有一个任务发送，避免 DMA 描述符冲突）
    if (xSemaphoreTake(xTxSemaphore, 250))
	{
        // 初始化发送参数（从当前待配置的 TX 描述符开始，获取缓冲区地址）
        DmaTxDesc = DMATxDescToSet;
        buffer = (uint8_t*)(DmaTxDesc->Buffer1Addr);
        bufferoffset = 0;

		// 遍历 pbuf 链表（pbuf 可能是链式结构，需拼接所有段数据）
		for (q = p; q != NULL; q = q->next)
		{
            // 检查当前 TX 描述符是否被 DMA 占用（OWN 位为 1 表示 DMA 正在使用，发送失败）
            if ((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
            {
                goto error; // 跳转到错误处理，释放信号量
            }

            // 获取当前 pbuf 段的有效数据长度，初始化剩余待复制字节数
            byteslefttocopy = q->len;
            payloadoffset = 0;

			// 处理单个 pbuf 段数据超过 DMA 缓冲区大小的情况（需分多个缓冲区发送）
            while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE)
            {
                // 复制当前缓冲区能容纳的最大数据（从 pbuf 到 DMA 发送缓冲区）
                memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset),  // 目标地址：当前缓冲区 + 偏移
                       (uint8_t*)((uint8_t*)q->payload + payloadoffset), // 源地址：当前 pbuf payload + 偏移
                       (ETH_TX_BUF_SIZE - bufferoffset));         // 复制长度：缓冲区剩余空间

                // 切换到下一个 TX 描述符（链式结构）
                DmaTxDesc = (ETH_DMADESCTypeDef *)(DmaTxDesc->Buffer2NextDescAddr);
                // 检查下一个描述符是否被占用
                if ((DmaTxDesc->Status & ETH_DMATxDesc_OWN) != (uint32_t)RESET)
                {
                    goto error;
                }

                // 更新参数：指向新缓冲区，更新剩余待复制字节数、总长度、偏移
                buffer = (u8 *)(DmaTxDesc->Buffer1Addr);
                byteslefttocopy -= (ETH_TX_BUF_SIZE - bufferoffset);
                payloadoffset += (ETH_TX_BUF_SIZE - bufferoffset);
                framelength += (ETH_TX_BUF_SIZE - bufferoffset);
                bufferoffset = 0; // 新缓冲区偏移从 0 开始
            }
            // 复制当前 pbuf 段的剩余数据（单个缓冲区可容纳，直接复制）
            memcpy((uint8_t*)((uint8_t*)buffer + bufferoffset), (uint8_t*)((uint8_t*)q->payload + payloadoffset), byteslefttocopy);
            // 更新缓冲区偏移和总帧长度
            bufferoffset += byteslefttocopy;
            framelength += byteslefttocopy;
		}
        // 配置 DMA 描述符，触发发送（设置帧长度、启动 DMA 发送）
        ETH_Prepare_Transmit_Descriptors(framelength);

		// 错误处理与信号量释放（无论成功/失败，都需释放发送信号量）
		error:
			xSemaphoreGive(xTxSemaphore);
	}

    // 简化处理：返回成功（实际项目需根据 DMA 状态判断是否发送成功）
    return ERR_OK;
}

/**
 * 中间层数据包发送（被 lwIP 调用，将 pbuf 中的数据通过发送任务发送）
 *
 * @param netif lwIP 网络接口结构体（当前发送网口）
 * @param p 要发送的 MAC 数据包（例如包含 MAC 地址和类型的 IP 数据包）
 * @return 成功返回ERR_OK，否则err_t值
 */
static err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p)
{
    netif = NULL;
    void *msg;
  
    msg = p;
  
    if(sys_mbox_trypost(&eth_tx_mb, &msg) == ERR_OK)
    {
        PRINT_INFO("sys_mbox_trypost ok\n");
        xSemaphoreTake(tx_sem, portMAX_DELAY);
    }

    return ERR_OK; 
}

/**
 * 以太网发送任务
 * 
 * @param pParams: lwip 网络接口指针
 */
static void ethernetif_output(void *pParams)
{
	struct pbuf *p;
	struct netif *netif;

	netif = (struct netif*) pParams;
  
	for (;;)
  	{
    	if (sys_arch_mbox_fetch(&eth_tx_mb, (void**)&p, 0) == ERR_OK)
    	{
      		PRINT_DEBUG("sys_arch_mbox_fetch ok\n");
      
      		if (p != NULL)
     		{
				if (low_level_output(netif, p) == ERR_OK)
				{
					PRINT_DEBUG("low_level_output ok\n");
				}
      		}
      
      		/* send ACK */
      		sys_sem_signal(&tx_sem);
    	}
  	}
}


/**
 * 获取ETH接收数据包的字节
 *
 * @param netif 网络接口结构体指针
 * @return 接收数据包（包括MAC头部）的pbuf指针，失败内存错误时为NULL
 */
static struct pbuf* low_level_input(struct netif *netif)
{
	struct pbuf *p, *q;        // p: 分配的 pbuf 主指针；q: 用于遍历 pbuf 链
	FrameTypeDef frame;        // 帧信息结构体（包含长度、缓冲区地址、描述符等）
	uint8_t* buffer;           // 指向当前接收数据缓冲区
	volatile ETH_DMADESCTypeDef *DMARxDesc; // 当前接收描述符指针

	uint32_t bufferoffset;     // 当前缓冲区数据偏移量
	uint32_t payloadoffset;    // 当前 pbuf 数据偏移量
	uint32_t byteslefttocopy;  // 剩余需要复制的字节数

	/* 从以太网 DMA 获取一个已经接收到的数据包帧 */
	frame = ETH_Get_Received_Frame_interrupt();

	/* 获取数据包缓冲区地址 */
	buffer = (uint8_t *)frame.buffer;// 指向数据包内容缓冲区
	
	/* 数据包长度等于0，数据无效 */
	if (frame.length == 0)
	{
		return NULL;
	}
	else
	{
		/* 从 LwIP 内存池分配一个 pbuf 链，类型为 PBUF_RAW（包含 MAC 头）， 长度为 len，使用 PBUF_POOL 方式分配（从内存池分配） */
		p = pbuf_alloc(PBUF_RAW, frame.length, PBUF_POOL);
		PRINT_DEBUG("Receive Frame Len : %d\r\n", frame.length);
	}
	/* 如果 pbuf 分配成功，则将数据从硬件缓冲区复制到 pbuf */
	if (p != NULL)
	{
		DMARxDesc = frame.descriptor; // 获取第一个接收描述符
		bufferoffset = 0;             // 从缓冲区起始位置开始复制

		/* 遍历 pbuf 链（可能是多段内存块） */
		for (q = p; q != NULL; q = q->next)
		{
			byteslefttocopy = q->len; // 当前 pbuf 段需要的数据长度
			payloadoffset = 0;        // 当前 pbuf 段的偏移量
			
			/* 如果当前 pbuf 段剩余空间不足以装下缓冲区中的数据，则需要分多次复制，跨多个 DMA 缓冲区 */
			while( (byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE )
			{
				/* 复制数据：从硬件缓冲区到当前 pbuf 段 */
				memcpy((uint8_t*)q->payload + payloadoffset, (uint8_t*)buffer + bufferoffset, ETH_RX_BUF_SIZE - bufferoffset);

				/* 移动到下一个 DMA 接收描述符 */
				DMARxDesc = (ETH_DMADESCTypeDef *)DMARxDesc->Buffer2NextDescAddr;
				buffer = (unsigned char *)DMARxDesc->Buffer1Addr;

				/* 更新剩余需要复制的数据量 */
				byteslefttocopy -= (ETH_RX_BUF_SIZE - bufferoffset);
				payloadoffset += (ETH_RX_BUF_SIZE - bufferoffset);
				bufferoffset = 0;
			}

			/* 复制剩余的数据到当前 pbuf 段 */
			memcpy((uint8_t*)q->payload + payloadoffset, (uint8_t*)buffer + bufferoffset, byteslefttocopy);
			bufferoffset += byteslefttocopy;
		}
	}

	/* 将用过的接收描述符释放给 DMA，让其可以重新用于接收新数据 */
	DMARxDesc = frame.descriptor;
	/* 将缓冲区交还给DMA */
	for (int i = 0; i < DMA_RX_FRAME_infos->Seg_Count; i++)
	{ 
		DMARxDesc->Status |= ETH_DMARxDesc_OWN;
		DMARxDesc = (ETH_DMADESCTypeDef *)DMARxDesc->Buffer2NextDescAddr;
	}

	/* 清空接收帧的段计数 */
	DMA_RX_FRAME_infos->Seg_Count = 0;
	/* 如果 DMA 处于接收缓冲区不可用状态，则清除标志并恢复接收 */
	if (ETH_GetDMAFlagStatus(ETH_DMA_FLAG_RBU) == SET)
	{
		// 清除 RBUS 标志
		ETH_DMAClearFlag(ETH_DMA_FLAG_RBU);
		// 恢复 DMA 接收
		ETH_ResumeDMAReception();
	}

	return p;
}

/**
 * 以太网接收任务
 * 
 * @param pParams: 网络接口指针
 */
static void ethernetif_input(void *pParams)
{
	struct netif *netif;
	struct pbuf *p;      // 指向接收到的数据包缓冲区

	netif = (struct netif*) pParams;
  
	for (;;)
  	{
		/* 等待接收信号量 */
    	if(xSemaphoreTake(ETH_Rx_xSemaphore, portMAX_DELAY) == pdTRUE)
    	{
			do
			{
				/* 获取数据包 */
				p = low_level_input(netif);

				if (p != NULL)
				{
					/* 发送完整数据包至tcpip_thread进行处理 */
					if (netif->input(p, netif) != ERR_OK)
					{
						pbuf_free(p);
						LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
					}
				}
				else
					break;
			} while (1);
    	}
	}
}



#if !LWIP_ARP
/**
 * 在ARP关闭的情况下，此函数需要由用户完成。
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return ERR_OK if ...
 */
static err_t low_level_output_arp_off(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
{
    struct eth_addr dst_mac;
    struct pbuf *new_p;
    struct eth_hdr *ethhdr;
    err_t err;

    // 1. 构造目标 MAC 地址
    if (ip4_addr_isbroadcast(ipaddr, netif) || ip4_addr_ismulticast(ipaddr))
	{
        // 广播或组播MAC
        eth_addr_copy_from(&dst_mac, &ethbroadcast);
    }
	else
	{
        // TODO: 这里需要你自己维护 IP->MAC 映射表
        // 这里举个例子，假设固定MAC
        dst_mac.addr[0] = 0x00;
        dst_mac.addr[1] = 0x11;
        dst_mac.addr[2] = 0x22;
        dst_mac.addr[3] = 0x33;
        dst_mac.addr[4] = 0x44;
        dst_mac.addr[5] = 0x55;
    }

    // 2. 分配一个新的 pbuf 来放以太网头
    new_p = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr), PBUF_RAM);
    if (new_p == NULL)
	{
        return ERR_MEM;
    }

    // 3. 填充以太网头
    ethhdr = (struct eth_hdr *)new_p->payload;
    eth_addr_copy(&ethhdr->dest, &dst_mac);
    eth_addr_copy(&ethhdr->src, (struct eth_addr *)netif->hwaddr);
    ethhdr->type = htons(ETHTYPE_IP);

    // 4. 将新的 pbuf 链到原数据 pbuf 前面
    new_p->next = q;

    // 5. 发送
	err = netif->linkoutput(netif, new_p);

    // 6. 释放我们分配的以太网头 pbuf（因为 low_level_output 已经发送数据）
    pbuf_free(new_p);

    return err;
}
#endif /* LWIP_ARP */ 

/**
 * 以太网网卡接口初始化函数
 * 
 * @param netif 此以太网接口的 lwip 网络接口结构
 * @return 如果loopif已初始化，则返回ERR_OK
 *         如果无法分配私有数据，则返回ERR_MEM
 *         发生错误时返回任何其他err_t类型的值
 */
err_t ethernetif_init(struct netif *netif)
{
	LWIP_ASSERT("netif != NULL", (netif != NULL));

#if LWIP_NETIF_HOSTNAME
	/* 初始化接口主机名 */
	netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */

	/* 设置网络接口名称（两个字符，如 "st"） */
	netif->name[0] = IFNAME0;
	netif->name[1] = IFNAME1;

#if LWIP_IPV4
	#if LWIP_ARP || LWIP_ETHERNET
		#if LWIP_ARP
			/* 指向 IP 层输出函数（ARP 协议层） */
			netif->output = etharp_output;
		#else
			/* 用户应在low_level_output_arp_off函数中编写自己的代码 */
			netif->output = low_level_output_arp_off;
		#endif /* LWIP_ARP */
	#endif /* LWIP_ARP || LWIP_ETHERNET */
#endif /* LWIP_IPV4 */
 
#if LWIP_IPV6
  	netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */

	/* 底层链路层发送函数 */
  	netif->linkoutput = low_level_output;
  
  	/* 底层硬件初始化函数 */
  	low_level_init(netif);

	/* 初始化 ARP 模块 */
	etharp_init();
	
	/* 启动 ARP 定时器 */
	sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
  	
	return ERR_OK;
}

/* ARP 定时器回调函数 */
static void arp_timer(void *arg)
{
	// 处理 ARP 定时任务
	etharp_tmr();
	/* 重新启动定时器（LWIP 定时器是一次性的，需要再次注册） */
	sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}








#if LWIP_NETIF_LINK_CALLBACK
/**
  * @brief  处理以太网链路状态变化（如链路通断）
  * @note   任务逻辑：等待链路中断信号量 → 检测 PHY 链路状态 → 更新 LwIP 网络接口状态
  * @param  pParams: 任务入口参数（此处传入 PHY 芯片地址，类型为 void*）
  * @retval None
  */
static void ETH_Link_Task(void * pParams)
{
	struct netif *netif = (struct netif*) pParams;
	ControlStatus ETH_Link_Status;

	ETH_Link_Status = (ControlStatus)netif_is_link_up(netif);
	/* 任务无限循环：不可退出 */
	for (;;)
	{
		#if 0
		/* 等待以太网链路信号量 */
		if (xSemaphoreTake(ETH_Link_xSemaphore, 400) == pdTRUE)
		{
			/* 验证是否为链路状态变化中断（避免中断误触发） */
			if ((ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_ISR) & PHY_ISR_LINK_STATUS) != 0)
			{
				/* 读取 PHY 状态寄存器（PHY_SR），获取当前实际链路状态 */
				if ( ( ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_BSR) & PHY_Linked_Status) != 0 )
				{
					/* 链路已连通：调用 LwIP 接口函数设置网络接口为"链路_up"状态 */
					netif_set_link_up(netif);
					PRINT_INFO("ETH Link UP\r\n");
				}
				else
				{
					/* 链路已断开：调用 LwIP 接口函数设置网络接口为"链路_down"状态 */
					netif_set_link_down(netif);
					PRINT_INFO("ETH Link Down\r\n");
				}
			}
		}
		#else
		{
			ControlStatus New_State = (ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_BSR) & PHY_Linked_Status) != RESET ? ENABLE : DISABLE;

			/* 读取 PHY 状态寄存器（PHY_SR），获取当前实际链路状态 */
			if ((New_State == ENABLE) && (ETH_Link_Status == DISABLE))
			{
				ETH_Link_Status = ENABLE;
				/* 链路已连通：调用 LwIP 接口函数设置网络接口为"链路_up"状态 */
				netif_set_link_up(netif);
				PRINT_INFO("ETH Link UP\r\n");
			}
			else if ((New_State == DISABLE) && (ETH_Link_Status == ENABLE))
			{
				ETH_Link_Status = DISABLE;
				/* 链路已断开：调用 LwIP 接口函数设置网络接口为"链路_down"状态 */
				netif_set_link_down(netif);
				PRINT_INFO("ETH Link Down\r\n");
			}
			vTaskDelay(300);
		}
		#endif
	}
}

/**
 * @brief  链接回调函数，此函数在链接状态改变时被调用,用于更新底层驱动程序配置。
 * @param  netif: The network interface
 * @retval None
 */
void ethernetif_update_config(struct netif *netif)
{
	extern ETH_InitTypeDef ETH_InitStructure;

	volatile uint32_t tickstart = 0; // 超时计数器
	uint32_t RegValue = 0;           // 用于存储寄存器值

  	if (netif_is_link_up(netif))
  	{
    	/* 如果 PHY 开启了自动协商功能 */
    	if (ETH_InitStructure.ETH_AutoNegotiation != ETH_AutoNegotiation_Disable)
		{
			/* 重启自动协商 */
			ETH_WritePHYRegister(ETHERNET_PHY_ADDRESS, PHY_BCR, PHY_AutoNegotiation);
		
			/* Get tick */
			tickstart = sys_now();
      
			/* 等待自动协商完成 */
			do
			{
				RegValue = ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_BSR);
				
				/* 检查超时（1秒）*/
				if ((sys_now() - tickstart ) > 1000)
				{     
					/* 若出现超时情况 */
					goto error;
				}   
			} while (((RegValue & PHY_AutoNego_Complete) != PHY_AutoNego_Complete));
      
			/* 读取自动协商的结果 */
			RegValue = ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_SR);
      
			/* 根据协商结果设置 MAC 双工模式 */
			if((RegValue & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
			{
				/* 按照自动协商将以太网双工模式设置为全双工 */
				ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
			}
			else
			{
				/* 按照自动协商将以太网双工模式设置为半双工 */
				ETH_InitStructure.ETH_Mode = ETH_Mode_HalfDuplex;
			}

			/* 根据协商结果设置 MAC 速率 */
			if(RegValue & PHY_SPEED_STATUS)
			{  
				/* 按照自动协商将以太网速度设置为10M */
				ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
			}
			else
			{   
				/* 按照自动协商将以太网速度设置为100兆 */
				ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
			}

			/* 更新 MAC 控制寄存器 MACCR */
			if (ETH_Init(&ETH_InitStructure, ETHERNET_PHY_ADDRESS) == ETH_SUCCESS)
			{
				/* 开启中断 */
				ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T, ENABLE);
			}
    	}
    	else /* 自动协商关闭 */
    	{
    	error :
			/* 检查参数 */
			assert_param(IS_ETH_SPEED(ETH_InitStructure.ETH_Speed));
			assert_param(IS_ETH_DUPLEX_MODE(ETH_InitStructure.ETH_Mode));
			
			/* 将MAC速度和双工模式设置到PHY */
			ETH_WritePHYRegister(ETHERNET_PHY_ADDRESS, PHY_BCR, ((uint16_t)(ETH_InitStructure.ETH_Mode >> 3) | (uint16_t)(ETH_InitStructure.ETH_Speed >> 1)));
		}

		/* 启动 MAC 接收/发送 */
		ETH_Start();
		/* 标记网络接口为可用 */
		netif_set_up(netif); 
		PRINT_INFO("ETH_Start\r\n");
  	}
  	else
  	{
		/* 停止 MAC 接收/发送 */
		ETH_Stop();
		/* 标记网络接口为不可用 */
    	netif_set_down(netif);
		PRINT_INFO("ETH_Stop\r\n");
  	}

  	ethernetif_notify_conn_changed(netif);
}


/**
  * @brief  此函数通知用户有关链接状态的更改。
  * @param  netif: the network interface
  * @retval None
  */
__weak void ethernetif_notify_conn_changed(struct netif *netif)
{
	PRINT_INFO("ethernetif_notify_conn_changed\r\n");
   /* 注意：当需要回调时，此函数可在用户文件中实现 */
}
#endif /* LWIP_NETIF_LINK_CALLBACK */


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

